package graphics;
/*
 * Zombinoes: Peter Mosher, Michael Pitts
 * TCSS 491 - Computational Worlds
 * Project 1
 */

import java.util.List;

import javax.media.opengl.GL2;


/**
 * This is a node in a graphics tree, it can be rotated, translated and scaled before
 * rendering.
 * @author Michael Pitts, Peter Mosher
 * @version Jan 23, 2012
 */
public abstract class AbstractNode implements Node {
	
	/** The translation data. */
	private float trans_x, trans_y, trans_z;
	
	/** The scale data. */
	private float scale_x = 1f, scale_y = 1f, scale_z = 1f;
	
	/** The rotation data. */
	private float angle, rotate_x, rotate_y, rotate_z;
	
	/** If true, this Node was selected in a preceding test. */
	protected boolean my_selected;
	
	@Override public void display(final GL2 the_gl) {
		the_gl.glPushMatrix();
		transform(the_gl);
		render(the_gl);
		the_gl.glPopMatrix();
	}
	
	@Override public boolean testSelect(final GL2 the_gl) {
		the_gl.glPushMatrix();
		transform(the_gl);
		my_selected = renderTest(the_gl);
		the_gl.glPopMatrix();
		return my_selected;
	}
	
	@Override public synchronized void setRotate(final float the_angle, 
			final float the_rotate_x, final float the_rotate_y, 
			final float the_rotate_z) {
		angle = the_angle;
		rotate_x = the_rotate_x;
		rotate_y = the_rotate_y;
		rotate_z = the_rotate_z;
	}
	
	@Override public synchronized void setScale(final float the_scale_x, final float the_scale_y, 
			final float the_scale_z) {
		scale_x = the_scale_x;
		scale_y = the_scale_y;
		scale_z = the_scale_z;
	}
	
	@Override public synchronized void setTranslate(final float the_trans_x, 
			final float the_trans_y, final float the_trans_z) {
		trans_x = the_trans_x;
		trans_y = the_trans_y;
		trans_z = the_trans_z;
	}
	
	/**
	 * Transforms this node and all child nodes.
	 * @param the_gl is the graphics object.
	 */
	protected synchronized void transform(final GL2 the_gl) {
		if (trans_x != 0 || trans_y != 0 || trans_z != 0) {
			the_gl.glTranslatef(trans_x, trans_y, trans_z);
		}
		if (scale_x != 0 || scale_y != 0 || scale_z != 0 ) {
			the_gl.glScalef(scale_x, scale_y, scale_z);
		}
		if (angle != 0) {
			the_gl.glRotatef(angle, rotate_x, rotate_y, rotate_z);
		}
	}
	
	@Override public float getRotateAngle() {return angle;}
	
	@Override public float getRotateX() {return rotate_x;}
	
	@Override public float getRotateY() {return rotate_y;}
	
	@Override public float getRotateZ() {return rotate_z;}
	
	@Override public float getScaleX() {return scale_x;}
	
	@Override public float getScaleY() {return scale_y;}
	
	@Override public float getScaleZ() {return scale_z;}
	
	@Override public float getTranslateX() {return trans_x;}
	
	@Override public float getTranslateY() {return trans_y;}
	
	@Override public float getTranslateZ() {return trans_z;}
	
	@Override public boolean isSelected() {
		return my_selected;
	}
	
	@Override public void clearSelect() {
		my_selected = false;
	}
	
	@Override public List<Node> getChildren() {
		return null;
	}
	
	@Override public void update(final Object... the_data) {
		// do nothing for now
	}
	
	/**
	 * Renders the actual data for this node, or calls display on its children.
	 * @param the_gl is the graphics object.
	 */
	protected abstract void render(final GL2 the_gl);
	
	/**
	 * Tests the actual data for this node, or calls renderTest on its children.
	 * @param the_gl is the graphics object.
	 * @return true if this node, or one of it's children was selected.
	 */
	protected abstract boolean renderTest(final GL2 the_gl);
}
